//
// Created by Scave on 2023/11/9.
//

#ifndef RIDER3D_SUPPOSITION_H
#define RIDER3D_SUPPOSITION_H

#include <array>
#include "Define.h"

NS_RIDER_BEGIN

#pragma pack(push, 1)
    /// Point of screen(such as phone screen),
    /// Starting from the top left corner, the range is from 0 to the width(x) or height(y) of the screen
    struct ScreenPoint {
        UInt16 x;
        UInt16 y;
    };

    struct Size {
        UInt16 width;
        UInt16 height;

        bool operator ==(const Size& size) const {
            return this->width == size.width && this->height == size.height;
        }
    };

    struct Rect {
        UInt16 x = 0;
        UInt16 y = 0;
        UInt16 w = 0;
        UInt16 h = 0;

        bool Valid() const {
            return w > 0 && h > 0;
        }
    };

    /// Point of Normalized Device Coordinate,
    /// the range is (-1, 1)
    struct NdcPoint {
        float x;
        float y;
        float z;

        static NdcPoint Add(const NdcPoint& a, const NdcPoint& b);
        static NdcPoint Sub(const NdcPoint& a, const NdcPoint& b);
        static NdcPoint Scalar(const NdcPoint& a, float b);
        static float Dot(const NdcPoint& a, const NdcPoint& b);
        static NdcPoint Cross(const NdcPoint& a, const NdcPoint& b);
        static NdcPoint Normalize(const NdcPoint& a);
        static float Length(const NdcPoint& a);
        static float Distance(const NdcPoint& a, const NdcPoint& b);
        static NdcPoint Center(const NdcPoint& a, const NdcPoint& b);
    };

    /// Point of texture,
    /// Starting from the bottom left corner, the range is (0, 1)
    struct TextureUVPoint {
        float u;
        float v;
    };

    struct NdcRect {
        float x;
        float y;
        float w;
        float h;
    };

    struct Color {
        float r;
        float g;
        float b;
        float a;
    };

    typedef NS_RIDER::NdcPoint Number3D;
    typedef NS_RIDER::NdcPoint Vec3;
    typedef NS_RIDER::TextureUVPoint UV;

    struct Vertex {
        Vec3 position = {0, 0, 0};
        Vec3 normal = {0, 0, 0};
        UV uv = {0, 0};
        Color color = {1, 1, 1, 1};
    };
#pragma pack(pop)

    struct Quaternion;
    struct Mat4 {
        Mat4();

        explicit Mat4(float* data);

        void Scale(const Vec3& scale);

        void Scale(float sx, float sy, float sz);

        void Rotate(const Quaternion& q);

        void Rotate(float rx, float ry, float rz);

        void Translate(const Vec3& translation);

        void Translate(float tx, float ty, float tz);

        void SRT(const Vec3& scale, const Quaternion& rotation, const Vec3& translation);

        void LookAt(const Vec3& eye, const Vec3& at, const Vec3& up = { 0.0f, 1.0f, 0.0f });

        void Perspective(float fov, float aspect, float near, float far);

        void Orthographic(float left, float right, float bottom, float top, float near, float far, float offset);

        Mat4 Mul(const Mat4& other);

        Mat4 Inverse();

        Mat4 Transpose();

        const float* Data() const;

        bool Equals(const Mat4& other, float tolerance = 1e-6f) const;

        bool operator ==(const Mat4& other) const;

        bool operator !=(const Mat4& other) const;

    private:
        std::array<float, 16> array16;
    };

    struct Quaternion {
        float w = 1;
        float x = 0;
        float y = 0;
        float z = 0;

        /// 从欧拉角构建四元数
        /// \param pitch 俯仰角（绕X轴旋转角度）
        /// \param yaw 偏航角（绕Y轴旋转角度）
        /// \param roll 横滚角（绕Z轴旋转角度）
        static Quaternion FromEuler(float pitch, float yaw, float roll);

        /// 四元数模长
        float Norm() const;

        /// 归一化（避免旋转失真）
        Quaternion Normalized() const;

        /// 获取四元数的共轭（逆）
        Quaternion Conjugate() const;

        /// 四元数相乘
        /// \param other 另一个四元数
        Quaternion Mul(const Quaternion& other) const;

        /// 基于当前四元数增加旋转角度
        /// \param pitch 俯仰角（绕X轴旋转角度）
        /// \param yaw 偏航角（绕Y轴旋转角度）
        /// \param roll 横滚角（绕Z轴旋转角度）
        Quaternion& AddRotation(float pitch, float yaw, float roll);

        /// 将四元数转换为指向的方向向量，以默认朝向(0, 0, -1)为准
        Vec3 ToDirection() const;

        /// 转换为欧拉角
        Vec3 ToEuler() const;

        /// 转换为四维矩阵
        Mat4 ToMat4();
    };

    struct Colors {
        const static Color Red;
        const static Color Green;
        const static Color Blue;
        const static Color Black;
        const static Color White;
        const static Color Orange;
        const static Color Purple;
        const static Color Cyan;
    };

    struct Vectors {
        const static Vec3 Forward;
        const static Vec3 Back;
        const static Vec3 Left;
        const static Vec3 Right;
        const static Vec3 Up;
        const static Vec3 Down;
        const static Vec3 Invalid;
    };

    inline static bool operator==(const NdcPoint& a, const NdcPoint& b) {
        return a.x == b.x &&
               a.y == b.y &&
               a.z == b.z;
    }

NS_RIDER_END

#endif //RIDER3D_SUPPOSITION_H
